home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / System 7.0 Samples / AEObject-Edition1.0.2 Sample / AppleEventCore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-09  |  26.5 KB  |  637 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. *
  3. *  Apple Developer Technical Support
  4. *
  5. *  AppleEvent specific routines
  6. *
  7. *  Program:    AEObject-Edition Sample
  8. *  File:       AppleEventCore.c - C Source
  9. *
  10. *  by:         C.K. Haun <TR>
  11. *
  12. *  Copyright © 1990-1992 Apple Computer, Inc.
  13. *  All rights reserved.
  14. *
  15. *------------------------------------------------------------------------------
  16. * This file handles the generic AppleEvent handlers, as well as intialization
  17. * and installing the handlers I'll need for this application.
  18. * Also installs my coercion handlers and has the interaction Idle proc.
  19. * Other, more specific AE handling (like edition functions) are in the functional 
  20. * area files.
  21. * Functions that deal specifically with AppleEvent™ Objects are in the 
  22. * file AEObject.c.
  23. *----------------------------------------------------------------------------*/
  24. /* AESample v1: Removed all ShowMe error notifications, replaced with macro to display */
  25. /* errors non-intrusively in AESatus window */
  26.  
  27. #define __AEM__
  28.  
  29. #pragma segment Main
  30. /* DoHighLevel will be in main, just because */
  31. #include "Sampdefines.h"
  32.  
  33.  
  34.  
  35. /* DoHighLevel processes our high level events */
  36. /* All the HLEs that come into my application get dispatched to here. */
  37. /* All I do is call AEProcessAppleEvent, because I do not support any */
  38. /* other types of High Level Events, justs AEs. */
  39. void DoHighLevel(EventRecord AERecord)
  40. {
  41.     OSErr fred2;
  42.     /* Process the event. */
  43.     /* Here's what happens; 
  44.     1) If this is an AppleEvent, and we have a handler installed for this event, 
  45.     AEProcessAppleEvent jumps to that handler 
  46.     else
  47.     2) If there is a system handler for this event, AEProcessAppleEvent jumps to that
  48.     else
  49.     3) return errEventNotHandled.
  50.     */
  51.     /* •••• NOTE: If you are sending AppleEvents to yourself (using a PSN of kCurrentProcess */
  52.     /* in the address AEDesc to AECreateAppleEvent) then events sent to yourself that */
  53.     /* way will NOT come here!  They will be dispatched directly to the  */
  54.     /* correct handler by the AppleEvent manager!  Try it in this sample. */
  55.     fred2 = AEProcessAppleEvent(&AERecord);
  56.     if ((fred2 != userCanceledErr) && (fred2 != noErr) && (fred2 != errAEEventNotHandled))
  57.         mAEErrorDisplay("\pAppleEvent Proccessing.", fred2)
  58.         /* if it was a userCanceledErr (from the quit routine) and the reply has been */
  59.         /* sent from there already */
  60.         /* if it's a errAEEventNotHandled, then someone sent us  an event we're not prepared for, */
  61.         /* that is not a reason to put up a dialog.  Since anyone can send us events, then */
  62.         /* we could get all kinds of stray stuff, so just ignore it. */
  63.         /* you may want to check for debugging reasons */        
  64. }
  65.  
  66. /* end DoHighLevel */
  67.  
  68. #pragma segment AppleEvents
  69. /***************************************************************************************
  70.  
  71. MissedAnyParameters
  72.  
  73. Used to check for any unread required parameters. Returns true if we missed at
  74. least one.
  75.  
  76. *****************************************************************************************/
  77. Boolean MissedAnyParameters(AppleEvent *message)
  78. {
  79.     OSErr err;
  80.     DescType ignoredActualType;
  81.     AEKeyword missedKeyword;
  82.     Size ignoredActualSize;
  83.     EventRecord event;
  84.     
  85.     err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeKeyword, &ignoredActualType, (Ptr)&missedKeyword,
  86.                             sizeof(missedKeyword), &ignoredActualSize);
  87.     
  88.     /* no error means that we found some more.*/
  89.     
  90.     if (!err) {
  91.         event.message = *(long *)&ignoredActualType;
  92.         event.where = *(Point *)&missedKeyword;
  93.         mAEErrorDisplay("\pMissedAnyParameters: got parameters I don't know what to do with.", err)
  94.         err = errAEEventNotHandled;
  95.     }
  96.     
  97.     /* errAEDescNotFound means that there are no more parameters. If we get */
  98.     /* an error code other than that, flag it. */
  99.     
  100.     else if (err != errAEDescNotFound) {
  101.         mAEErrorDisplay("\pMissedAnyParameters: after AEGetAttributeDesc.", err)
  102.         
  103.     }
  104.     return(err != errAEDescNotFound);
  105. }
  106.  
  107. /* This is the standard Open Application event.  You'll get this as one of the (if not the ) */
  108. /* first events in your application.  So, we open up a blank document */
  109. /* You will _NOT_ get this if you were launched with an event (like an 'odoc' or 'pdoc' ) */
  110. /* so do _not_ do application initialiaztion things here!  This routine may never */
  111. /* get called! */
  112. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  113. {
  114.     OSErr myErr = noErr;
  115. #pragma unused (messagein,refIn)
  116.     gCurrentReply = reply;
  117.  
  118.     ChangePlane(AddNewWindow(true));                        /* open our initial, blank window */
  119.     /* and make sure it's the front window */
  120.     
  121.     mAEErrorDisplay("\pOpen App Handler", myErr)
  122.     gCurrentReply = nil;
  123.     return(myErr);
  124. }
  125.  
  126. /* end AEOpenHandler */
  127.  
  128. /* Open Doc, opens our documents.  Remember, this can happen at application start AND */
  129. /* anytime else.  If your app is up and running and the user goes to the desktop, hilites one */
  130. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  131. /* handler will get called. Which means you don't do any initialization of globals here, or */
  132. /* anything else except open then doc.  */
  133. /* SO -- Do NOT assume that you are at app start time in this */
  134. /* routine, or bad things will surely happen to you. */
  135.  
  136. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  137. {
  138.     OSErr myErr = noErr;
  139. #pragma unused ( refIn)
  140.     gCurrentReply = reply;
  141.  
  142.     /* In previous versions I was coming to the front on this message.  This is _not_ */
  143.     /* the proper thing to do.  I have changed things to call AEInteractWithUser.  */
  144.     /*  The user (or the AEm will bring us forward if appropriate).  But we may _not_ be  */
  145.     /*required to come forward, it may be perfectly reasonable to stay in the background */
  146.     /* so don't do anything unless you really need to, like to put up a dialog */
  147.     /* which we don't have to, so just press on */
  148.     myErr = processOpenPrint(messagein, false);
  149.     gCurrentReply = nil;
  150.     return(myErr);
  151. }
  152.  
  153. /* Same logic as OpenDoc */
  154. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  155. {                                                           /* no printing handler in yet, so we'll ignore this */
  156.     /* the operation is functionally identical to the ODOC event, with the additon */
  157.     /* of calling your print routine.  */
  158. #pragma unused (refIn)
  159.     gCurrentReply = reply;
  160.     processOpenPrint(messagein, true);
  161.     gCurrentReply = nil;
  162.     return(noErr);
  163. }
  164.  
  165. /* Standard Quit event handler, to handle a Quit event from the Finder, for example.  */
  166. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life.  */
  167. /* OK, it's a few months after I wrote that comment, and I've seen a lot of code */
  168. /* come through DTS that calls ExitToShell from quit handlers.  Let me explain... */
  169. /* When an AppleEvent Handler is called (like this quit handler) you are ALMOST */
  170. /* 100% in your application world.  A5 is right, you can call any toolbox function, */
  171. /* you can call your own routines, everything _seems_ like you are in complete  */
  172. /* control.  Well, almost but not quite.  The routine has been dispatch to from the */
  173. /* AppleEvent Manager's space, so you _must_ return to that at some point! */
  174. /* Which is why you can't call ETS from here.  When you call ExitToShell from an */
  175. /* AE Handler, the most likely thing that happens is the FInder quits, and your  */
  176. /* application keeps running.  Which ain't what you want, y'know? */
  177. /* so, DON'T CALL EXITTOSHELL FROM AN APPLEEVENT HANDLER!!!!!!!!!!!!!! */
  178. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  179. {
  180. #pragma unused (messagein,refIn)
  181.     OSErr theErr;
  182.     Str32 userCanx;
  183.     gCurrentReply = reply;
  184.     theErr = PrepQuit();                                    /* prepQuit sets the Stop flag for us.  It does _NOT_ quit, you */
  185.     /* should NEVER quit from an AppleEvent handler.  Calling */
  186.     /* ExitToShell here would blow things up */
  187.     
  188.     if (!theErr){
  189.     gCurrentReply = nil;
  190.         return(noErr);}
  191.     if (theErr == (userCanceledErr)) {
  192.         /* reply to the application that told us to quit */
  193.         GetIndString(userCanx,kGeneralStrings,kUCanxString);
  194.         AEPutParamPtr(reply, keyErrorNumber, typeLongInteger, (Ptr)&theErr, sizeof(OSErr));
  195.         AEPutParamPtr(reply, keyErrorString, typeChar, (Ptr)&userCanx, userCanx[0]);
  196.     }
  197.     gCurrentReply = nil;
  198.         return(theErr);
  199.     
  200. }
  201.  
  202. /* This is the 'ansr', or answer, handler.  You need this if you ever want to */
  203. /* use QueueReply as an option to AESend (which you will) since the reply  */
  204. /* is going to be coming in through your event loop like any other  */
  205. /* AppleEvent.   So here it is */
  206. pascal OSErr AEAnswerHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  207. {
  208. #pragma unused (refIn) 
  209.     OSErr myErr = noErr;
  210.         gCurrentReply = reply;
  211.     mVerboseOutput("\p\nGot an answer from an event")
  212.     DisplayReturnedData((AEDesc *)messagein);
  213.     gCurrentReply = nil;
  214.     return(myErr);
  215.     /* •••• NOTE:  One thing you may want to consider, and it's a side-effect of */
  216.     /* the AppleEvent manager's direct dispatching of events if you send them to yourself */
  217.     /* using the kCurrentProcess Process Serial Number constant. */
  218.     /* If you use kCurrentProcess, then the AppleEvent manager will directly dispatch */
  219.     /* to the AppleEvent handler, the event will _not_ go through WaitNextEvent. */
  220.     /* Normally, that's a very good thing.  But there is one potential problem.... */
  221.     /* It means that kQueueReply doesn't quite work the way you think it will when sending to */
  222.     /* yourself.  The reply will _not_ be put in the event queue, instead this Answer hander */
  223.     /* will be called directly.  And if you reply from the answer handler, that will dispatch right  */
  224.     /* back to itself.  And so on.  So be aware that Queued replies are _not_ really  */
  225.     /* queued when you are using kCurrentProcess! */
  226. }
  227.  
  228.  
  229. /* my routine to snatch a section handle out of an AppleEvent */
  230. OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection)
  231. {
  232.     DescType thisType;
  233.     Size returnedSize;
  234.     return(AEGetKeyPtr(AEin, keyDirectObject, typeSectionH, &thisType, (Ptr)theSection, sizeof(theSection), &returnedSize));
  235. }
  236.  
  237. /* processOpenPrint handles ODOC and PDOC events.  Both events open a document, one prints it */
  238. OSErr processOpenPrint(AppleEvent *messagein, Boolean printIt)
  239. {
  240.     OSErr err;
  241.     OSErr err2;
  242.     AEDesc theDesc;
  243.     FSSpec theFSS;
  244.     register qq;
  245.     long numFilesToOpen;
  246.     AEKeyword ignoredKeyWord;
  247.     DescType ignoredType;
  248.     Size ignoredSize;
  249.     WindowPtr tWind;
  250.     err = AEGetParamDesc(messagein, keyDirectObject, typeAEList, &theDesc);
  251.     if (err) {
  252.         mAEErrorDisplay("\pGetParamDesc error in Open/Print", err)
  253.     }
  254.     if (!MissedAnyParameters(messagein)) {
  255.         
  256.         /* Got all the parameters we need. Now, go through the direct object, */
  257.         /* see what type it is, and parse it up. */
  258.         
  259.         if (err = AECountItems(&theDesc, &numFilesToOpen)) {
  260.             mAEErrorDisplay("\pAECountItems error in Open/Print", err)
  261.         } else {
  262.             for (qq = 1; ((qq <= numFilesToOpen) && (!err)); ++qq) {
  263.                 if (err = AEGetNthPtr(&theDesc, qq, typeFSS, &ignoredKeyWord, &ignoredType, (Ptr)&theFSS, sizeof(theFSS),
  264.                                       &ignoredSize)) {
  265.                     mAEErrorDisplay("\pAEGetNthPtr in Open/Print", err)
  266.                     
  267.                 } else {
  268.                     FInfo fileInfo;
  269.                     FSpGetFInfo(&theFSS, &fileInfo);        /* make sure it's a data file */
  270.                     if (fileInfo.fdCreator == kMySignature && fileInfo.fdType == kMyDocumentFileType)
  271.                         tWind = OpenFile(&theFSS);
  272.                     else
  273.                         tWind = nil;                        /* they may have double clicked on the prefs file */
  274.                 }
  275.                 if (printIt && tWind != nil) {
  276.                     
  277.                     PrintIt(tWind, false);                  /* in Print.c.  Does not yet print, but the idea is there */
  278.                     CloseMyWindow(tWind);
  279.                 }
  280.             }                                               /* for qq = ... */
  281.         }                                                   /* AECountItems OK */
  282.     }                                                       /* Got all necessary parameters */
  283.     
  284.     if (err2 = AEDisposeDesc(&theDesc)) {
  285.         mAEErrorDisplay("\pAEDisposeDesc in Open/Print", err2)
  286.     }
  287.     return(err ? err : err2);
  288. }
  289.  
  290. /* This is an AppleEvent Idle function.  It can be passed to AEInteractWithUser */
  291. /* or AESend. */
  292. /* What it does is this; */
  293. /* If some AppleEvent thing is taking a really long time, the AppleEvent manager */
  294. /* will call WaitNextEvent FOR you (yeah, yeah, only one event loop per app, oh well) */
  295. /* and give you a result (limited) if you need to do something.  That something */
  296. /* will only be an update,activate,OSevent, or null event */
  297. pascal Boolean CommonIdleFunction(EventRecord *whatEvent, long *sleeping, RgnHandle *mouseRgn)
  298. {
  299.     extern Boolean gInBackground;
  300.     
  301.     extern RgnHandle mousergn;
  302.     switch (whatEvent->what) {
  303.         case updateEvt:
  304.             DrawIt((WindowPtr)whatEvent->message);          /* draw whatever window needs an update */
  305.             
  306.             break;
  307.         case activateEvt:
  308.             if (whatEvent->modifiers & activeFlag)
  309.                 DrawIt((WindowPtr)whatEvent->message);
  310.             break;
  311.         case app4Evt:                                       /* or kOSEvent, I'm old fashioned */
  312.             switch ((whatEvent->message >> 24) & 0x0FF) {       /* high byte of message */
  313.                 case suspendResumeMessage:                  /* suspend/resume is also an activate/deactivate */
  314.                     gInBackground = (whatEvent->message & kResumeMask) == 0;
  315.                     if (gInBackground) {
  316.                         SpitClip();                         /* export the clipboard please */
  317.                         /* deactivate the current TextEdit record as necessary */
  318.                         if (FrontWindow() != nil) {
  319.                             windowCHandle tempCH = (windowCHandle)GetWRefCon(FrontWindow());
  320.                             if ((*tempCH)->boxHandle != nil)
  321.                                 TEDeactivate((*tempCH)->boxHandle);
  322.                         }
  323.                     } else {
  324.                         if (FrontWindow() != nil) {
  325.                             windowCHandle tempCH = (windowCHandle)GetWRefCon(FrontWindow());
  326.                             if ((*tempCH)->boxHandle != nil)
  327.                                 TEActivate((*tempCH)->boxHandle);
  328.                         }
  329.                     }
  330.                     break;
  331.             }
  332.             break;
  333.         case nullEvent:
  334.             AdjustCursor(whatEvent->where, mousergn);
  335.             *sleeping = 20;                                  /* may as well sleep a while */
  336.             *mouseRgn = mousergn;
  337.             break;
  338.      
  339.     }
  340.     return(false);                                          /* If it takes for-ever I will wait, for you...  Sorry. */
  341. }
  342.  
  343. /* This function sends a GetData AppleEvent to someone, and displays the */
  344. /* results in the AEStatus window */
  345. void SendGetData(short which)
  346. {
  347.     AEDesc thisAddress;
  348.     AppleEvent theEvent;
  349.     AEDesc reply;
  350.     OSErr myErr = noErr;
  351.     /* first make an address */
  352.     MakeAddress(&thisAddress);
  353.     myErr = AECreateAppleEvent(kAECoreSuite, kAEGetData, &thisAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  354.     myErr = BuildGetDataEvent(&theEvent, which);            /* in AEObjects.c */
  355.     if (!myErr) {
  356.         /* reply may or may not be used, depending on the reply mode you have set */
  357.         myErr = DoSend(&theEvent, &reply);
  358.         if (!myErr) {
  359.             /* display the results, if we were in WaitReply */
  360.             if (gReplyMode == 1)
  361.                 DisplayReturnedData(&reply);
  362.         }
  363.     }
  364. }
  365. /* This function sends a SetData AppleEvent to someone, and displays the */
  366. /* results in the AEStatus window */
  367. void SendSetData(short which)
  368. {
  369.     AEDesc thisAddress;
  370.     AppleEvent theEvent;
  371.     AEDesc reply;
  372.     OSErr myErr = noErr;
  373.     /* first make an address */
  374.     MakeAddress(&thisAddress);
  375.     myErr = AECreateAppleEvent(kAECoreSuite, kAESetData, &thisAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  376.     myErr = BuildSetDataEvent(&theEvent, which);            /* in AEObjects.c */
  377.     if (!myErr) { 
  378.         DoSend(&theEvent, &reply);
  379.     }
  380. }
  381.  
  382.  
  383. /* Dialog box handler for the Interaction Settings you want to use for this sample */
  384. void SetInteractionLevels(void)
  385. {
  386.     /* call my common start routine and preset some buttons */
  387.     DialogPtr tdial = CommonDStart(kInteractionDialog, gLocalInteraction + 6, gAESendInteraction + 9);
  388.     short hitItem = 0;
  389.     /* save some stuff in case the user cancels */
  390.     short saveMode1 = gLocalInteraction;
  391.     short saveMode2 = gAESendInteraction;
  392.     short saveMode3 = gAESwitchLayer;
  393.     
  394.     /* one additial item to set */
  395.     SetCtlValue(SnatchHandle(tdial, kSwitchLItem), gAESwitchLayer);
  396.     /* run the dialog */
  397.     while (hitItem != ok && hitItem != cancel) {
  398.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &hitItem);
  399.         switch (hitItem) {
  400.             case kSelfIItem:
  401.             case kLocalIItem:
  402.             case kAllIItem:
  403.                 /* check boxes, just toggle them */
  404.                 SetCtlValue(SnatchHandle(tdial, gLocalInteraction + kSelfIItem), false);
  405.                 gLocalInteraction = hitItem - kSelfIItem;
  406.                 SetCtlValue(SnatchHandle(tdial, gLocalInteraction + kSelfIItem), true);
  407.                 
  408.                 break;
  409.                 
  410.             case kNeverIItem:
  411.             case kCanIItem:
  412.             case kAlwaysIItem:
  413.                 /* more toggleable checkboxes */
  414.                 SetCtlValue(SnatchHandle(tdial, gAESendInteraction + kNeverIItem), false);
  415.                 gAESendInteraction = hitItem - kNeverIItem;
  416.                 SetCtlValue(SnatchHandle(tdial, gAESendInteraction + kNeverIItem), true);
  417.                 
  418.                 break;
  419.             case kSwitchLItem:
  420.                 gAESwitchLayer = (gAESwitchLayer ? false : kAECanSwitchLayer);
  421.                 SetCtlValue(SnatchHandle(tdial, kSwitchLItem), gAESwitchLayer);
  422.                 break;
  423.             default:
  424.                 break;
  425.         }
  426.     }
  427.     DisposDialog(tdial);
  428.     if (hitItem == cancel) {
  429.         /* if they canceled, restore the old values */
  430.         gLocalInteraction = saveMode1;
  431.         gAESendInteraction = saveMode2;
  432.         gAESwitchLayer = saveMode3;
  433.         
  434.     } else {
  435.     /* set interaction levels to what the user picked  */
  436.     AESetInteractionAllowed(gLocalInteraction);
  437.     }
  438. }
  439.  
  440. /* Dialog box handler for the addressing mode you want to use for this sample */
  441. void SetTargetAddress(void)
  442. {
  443.     /* bring up dialog and preset some stuff */
  444.     DialogPtr tdial = CommonDStart(kAddressingDialog, gAddressMode + kSelfAddressCurrItem, 0);
  445.     short hitItem = 0;
  446.     short saveMode = gAddressMode;
  447.     /* if an address is already specified, draw it in the box */
  448.     ParamText(&targetName, "", "", "");
  449.     /* dim out the 'Select Target' button if the right check box is not set */
  450.     if (gAddressMode + kSelfAddressCurrItem != kOtherAppItem)
  451.         HiliteControl(SnatchHandle(tdial, kSelectProcItem), 255);       /* can't find the constant for dimmed, somebody tell me where it is,please */
  452.     /* run the dialog */
  453.     while (hitItem != ok && hitItem != cancel) {
  454.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &hitItem);
  455.         switch (hitItem) {
  456.             case kSelfAddressCurrItem:
  457.             case kSelfAddressPSNItem:
  458.             case kOtherAppItem:
  459.                 /* checkbox toggling, and also setting the hilite state of the 'Set Target' */
  460.                 /* button as necessary */
  461.                 SetCtlValue(SnatchHandle(tdial, gAddressMode + kSelfAddressCurrItem), false);
  462.                 gAddressMode = hitItem - kSelfAddressCurrItem;
  463.                 SetCtlValue(SnatchHandle(tdial, gAddressMode + kSelfAddressCurrItem), true);
  464.                 if (gAddressMode + kSelfAddressCurrItem != kOtherAppItem)
  465.                     HiliteControl(SnatchHandle(tdial, kSelectProcItem), 255);
  466.                 else
  467.                     HiliteControl(SnatchHandle(tdial, kSelectProcItem), 0);
  468.                 break;
  469.             case kSelectProcItem:
  470.                 /* Call the PPC browser to select a target */
  471.                 BrowseForTarget(&gTargetAddress);
  472.                 break;
  473.             default:
  474.                 break;
  475.         }
  476.     }
  477.     DisposDialog(tdial);
  478.     /* restore old mode if they canceled */
  479.     if (hitItem == cancel)
  480.         gAddressMode = saveMode;
  481.     
  482. }
  483.  
  484. /* Dialog box handler for the Reply Settings you want to use for this sample */
  485. void SetReplyMode(void)
  486. {
  487.     DialogPtr tdial = CommonDStart(kReplyModeDialog, gReplyMode + kNoReplyItem, 0);
  488.     short hitItem = 0;
  489.     short saveMode = gReplyMode;
  490.     
  491.     /* set up to gray out the 'no reply' button */
  492.     HiliteControl(SnatchHandle(tdial, kNoReplyItem), 255);
  493.     while (hitItem != ok && hitItem != cancel) {
  494.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &hitItem);
  495.         switch (hitItem) {
  496.             case kNoReplyItem:
  497.             case kWaitReplyItem:
  498.             case kQueueReplyItem:
  499.                 SetCtlValue(SnatchHandle(tdial, gReplyMode + kNoReplyItem), false);
  500.                 gReplyMode = hitItem - kNoReplyItem;
  501.                 SetCtlValue(SnatchHandle(tdial, gReplyMode + kNoReplyItem), true);
  502.                 break;
  503.             default:
  504.                 break;
  505.         }
  506.     }
  507.     DisposDialog(tdial);
  508.     if (hitItem == cancel)
  509.         gReplyMode = saveMode;
  510. }
  511.  
  512.  
  513. /*  CoerceBooleanToChar creates a desc that says True or False.  It's not a very */
  514. /* interesting coercion, but it's a nice sample.  I use it for my output window */
  515. pascal OSErr CoerceBooleanToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
  516. {
  517. #pragma unused (refCon)
  518.     OSErr myErr = noErr;
  519.     /* make sure everything is fine first */
  520.     if (origData != typeBoolean || toType != typeChar) {
  521.         /* something is goofy here */
  522.         myErr = errAECoercionFail;
  523.     } else {
  524.         /* a boolean should be two bytes. if it isn't, I'm confused */
  525.         if (theSize == sizeof(short)) {
  526.             short theBool = *((short *)inPtr);
  527.             short index;
  528.             Str32 theText;
  529.             index = theBool ? kTrueWord : kFalseWord;
  530.             GetIndString(theText, kGeneralStrings, index);
  531.             myErr = AECreateDesc(typeChar, (Ptr)&theText[1], theText[0], result);
  532.         } else {
  533.             myErr = errAECoercionFail;
  534.         }
  535.     }
  536.     return(myErr);
  537. }
  538.  
  539. /*  CoerceQDRectToChar is the same kinda thing */
  540. pascal OSErr CoerceQDRectToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
  541. {
  542. #pragma unused (theSize,refCon)
  543.     OSErr myErr = noErr;
  544.     /* make sure everything is fine first */
  545.     if (origData != typeQDRectangle || toType != typeChar) {
  546.         myErr = errAECoercionFail;
  547.     } else {
  548.         short *myRect = (short *)inPtr;
  549.         register qq;
  550.         Str255 theString;
  551.         Str32 tempString;
  552.         Str32 spaceString = "\p ";
  553.         
  554.         theString[0] = 0;
  555.         GetIndString(theString, kGeneralStrings, kSayRectangle);
  556.         for (qq = 0; qq < kFour; qq++) {
  557.             NumToString(*myRect, tempString);
  558.             AppendString(theString, tempString);
  559.             AppendString(theString, spaceString);
  560.             myRect = myRect + 1;                            /* I have had trouble with MPW C doing a += on a pointer, so I'll do it this way */
  561.         }
  562.         myErr = AECreateDesc(typeChar, (Ptr)&theString[1], theString[0], result);
  563.     }
  564.     return(myErr);
  565. }
  566.  
  567. /* these next two I really do find useful, dealing with Toolbox strings */
  568. pascal OSErr CoerceCharToPString(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
  569. {
  570. #pragma unused (origData,toType,refCon)
  571.     OSErr myErr = noErr;
  572.     Str255 theString;
  573.     theString[0] = theSize;
  574.     BlockMove(inPtr, (Ptr)&theString[1], theSize);
  575.     myErr = AECreateDesc(typeMyPString, (Ptr)&theString[0], theString[0] + 1, result);
  576.     
  577.     return(myErr);
  578. }
  579.  
  580. pascal OSErr CoercePStringToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result)
  581. {
  582. #pragma unused (origData,toType,refCon)
  583.     OSErr myErr = noErr;
  584.     myErr = AECreateDesc(typeChar, (Ptr)(inPtr + 1), theSize - 1, result);
  585.     
  586.     
  587.     return(myErr);
  588. }
  589.  
  590. /* CoerceAliasToTargetID takes an applicaiton alias and coerces it to a process target ID */
  591. /* Of course, to do this is needs to find and launch the application */
  592. /* This handler uses pointers to the data, since the AppleEvent managr can handle this type */
  593. /* of manipulation more efficiently than passing descs.  You can install a desc handler */
  594. /* instead, if you'd like. */
  595. /* I actually don't use this in this sample, but I left it in as an example */
  596. /* of a coercion handler */
  597. pascal OSErr CoerceAliasToTargetID(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *returnID)
  598. {
  599. #pragma unused (origData,toType,refCon)
  600.     OSErr myErr;
  601.     LaunchParamBlockRec launchThis;
  602.     FSSpec theSpec;
  603.     Boolean changed;
  604.     Handle theAlias = NewHandle(theSize);
  605.     HLock(theAlias);
  606.     BlockMove(inPtr, (Ptr)*theAlias, theSize);
  607.     HUnlock(theAlias);
  608.     launchThis.launchAppSpec = &theSpec;
  609.     /* the caller may have already done this, but it doesn't hurt to do it again */
  610.     myErr = ResolveAlias(nil, (AliasHandle)theAlias, launchThis.launchAppSpec, &changed);
  611.     if (myErr)
  612.         return(myErr);
  613.     /* launch the thing */
  614.     launchThis.launchBlockID = extendedBlock;
  615.     launchThis.launchEPBLength = extendedBlockLen;
  616.     launchThis.launchFileFlags = nil;
  617.     /* launchdontswitch because we just want to use the service.  Also, it may be a */
  618.     /* background only application, so like you don't want it to come up, y'know? */
  619.     launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch;
  620.     launchThis.launchAppParameters = nil;
  621.     myErr = LaunchApplication(&launchThis);
  622.     if (myErr) {
  623.         mAEErrorDisplay("\pLaunchApplication error", myErr)
  624.         return(myErr);
  625.     }
  626.     /* it launched.  the PSN has been stored in the launchProcessSN field, now we have to make */
  627.     /* that a target */
  628.     /* fill in all the details for the target */
  629.     /* we'll just use the PSN to communicate */
  630.     myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber), returnID);
  631.     mAEErrorDisplay("\pCreateDesc error after launch", myErr)
  632.     return(myErr);
  633. }
  634.  
  635.  
  636. #undef __AEM__
  637.